<?php
/**
 * thumbnail_party.class.php
 * Generate thumbnail from source image using GDlib or ImageMagick
 *
 * @author Mickey9801 <mickey9801@gmail.com>
 * @copyright copyright ComicParty.com 2006
 * @version 1.0.1
 * @package thumbnail_party
 * 
 * DESCRIPTION :
 * This class provide an abstract interface to generate thumbnail using GDlib or ImageMagick.
 * You can decide the dimenision of output thumbnail. The source image will be place inside the
 * thumbnail and resize in proportion based on the enlarge mode you have chosen.
 *
 * Thumbnail can be output as file or send to output device directly
 *
 * If background color assigned, the background of output thumbnail will be filled with color.
 * 
 * You can decide to enlarge source image when source image is smaller the thumbnail, or remain
 * unchange by setting enlarge mode. If background color assigned and enlarge mode switched off,
 * the source image will be placed in the middle of thumnail. Otherwise, the thumnail will
 * have same size as source image.
 *
 * The class will generate cache file to reduce work load
 *
 * When using GDlib, the class will alse check PHP memory usage to prevent error.
 *
 * Two types of error reporting machanism is provided in the class.
 * When use with thumbnail.php (direct output to browser), an image with error message will be
 * generate when there is any error.
 * When using the class alone, you may always keep track on any error by calling isError() method.
 * 
 * INSTALL :
 * 1. Extract all files and folders from thumbnail_party.zip file
 * 2. Assign write permission to 'cache/' directory for all user. i.e. chmod 777 cache
 * 3. Include thumbnail_party.class.php to your code, or use with thumbnail.php to obtain the
 *    thumbnail directly
 *
 * EXAMPLE :
 * <?php
 * require('thumbnail_party.class.php');
 * if (FALSE === ($thumb =& new thumbnail_party($intWidth, $intHeight, '#RRGGBB', 'jpg'))) {
 *	die($thumb->get_error_msg());
 * }
 * // Set ImageMagick Path
 * if (!$thumb->set_imagemagick_path('/path/to/imagemagick')) {
 * 	die($thumb->get_error_msg());
 * }
 * $thumb->intJPEGQuality = 85; // Assign picture quality for JPEG image
 *
 * // Select enlarge mode for source image that smaller then output size
 * $thumb->set_enlarge_mode(THUMBNAIL_ENLARGE_ALWAYS);
 * // Set source image path
 * if (!$thumb->set_source_file($strFile)) die($thumb->get_error_msg());
 * 
 * // Output image to browser
 * if (!$thumb->output()) die($thumb->get_error_msg());
 * ?>
 *
 * For result of thumbnail generated by the class, please check index.html
 * For usage of the class, please check thumbnail.php
 * 
 * USAGE :
 * To build thumbnail_party object :
 * $thumb =& thumbnail_party ($intWidth=100, $intHeight=100, $strColor=NULL, $strType='jpg', $strCacheDir=NULL)
 *
 * To assign a cache path :
 * set_cache_path ($strDir = NULL)
 * - If not provide a cache directory, by default will use 'cache/'. 
 *
 * To config ImageMagick Path :
 * set_imagemagick_path ($strIMPath = NULL)
 * -If you do not config this path, by default will use GDlib to manipulate image file
 *
 * To assign the source of thumbnail :
 * set_source_file ($strSourceFile)
 * - both absolute or relative path are acceptable
 *
 * To set image type of output image :
 * set_output_type ($strOutputType = 'jpg')
 * - possible values are 'jpg', 'jpeg, 'png', 'gif'
 *
 * To set output image size :
 * set_thumbnail_size ($intWidth = 100, $intHeight = 100)
 *
 * To set background color :
 * set_background ($strColor)
 * - format : '#RRGGBB' or 'RRGGBB'
 *
 * To set enlarge mode
 * set_enlarge_mode ($intEnlargeMode)
 * - possible value : THUMBNAIL_ENLARGE_NONE(0) or THUMBNAIL_ENLARGE_ALWAYS(1)
 *
 * To output thumbnail to browser directly
 * output ()
 *
 * To output thumbnail to browser directly
 * output ('/path/and/filename/of/output/thumbnail')
 *
 * To check if the object is error on last operation
 * isError ()
 * - return TRUE when error found
 *
 * To obtain the last error message
 * get_error_msg ()
 *
 * HISTORY :
 * Mickey9801 2006-05-22 19:38 HKT
 *       Rename ALLOWED_IMG_TYPE to TP_ALLOWED_IMG_TYPE to prevent dependency
 *       Fixed set_background() does not return correctly bug
 *       Fixed some minor bugs
 * Mickey9801 2006-05-22 03:38  HKT
 *       First edition launched
 *
 */

define('THUMBNAIL_ENLARGE_NONE', 0);
define('THUMBNAIL_ENLARGE_ALWAYS', 1);
define('TP_ALLOWED_IMG_TYPE', 'image/jpeg,image/pjpeg,image/gif,image/png');
define('IMAGEMAGICK_RESIZE_CMD', '%s -quality %d -resize %dx%d %s %s');
define('IMAGEMAGICK_RESIZE_FILLED_CMD', '%s %s -quality %d -resize %dx%d -size %dx%d xc:%s +swap -gravity center -composite %s');

class thumbnail_party {
	var $strSourceFile;
	var $intThumbnailWidth;
	var $intThumbnailHeight;
	var $strBgColor = NULL;
	var $strOutputType = 'jpg';
	var $intJPEGQuality = 85; // Picture quality for JPEG image. Max. value 100
	var $strCacheDir = 'cache/';
	var $strImageMagicPath = NULL; // Path to ImageMagick. Usually is '/usr/bin/convert' or '/usr/local/bin/convert'
	var $intEnlargeMode = THUMBNAIL_ENLARGE_NONE; // by default, keep the source in original size if the source smaller then output size (no enlarge)
	var $boolError = FALSE;
	var $strErrMsg = '';
	
	/**
	 * Constructor
	 *
	 * @param integer $intWidth Thumbnail width. Default 100.
	 * @param integer $intHeight Thumbnail height. Default 100.
	 * @param string $strColor Color string. Possible format : '#RRGGBB' & 'RRGGBB', Default NULL
	 * @param string $strType Thumbnail Type. Possible value : 'jpg', 'jpeg', 'gif' & 'png'. Default 'jpg'
	 * @param string $strCacheDir Cache path. Default NULL means using class default path 'cache/'
	 * @return boolean ture when no error
	 * @access public
	 */
	function thumbnail_party ($intWidth=100, $intHeight=100, $strColor=NULL, $strType='jpg', $strCacheDir=NULL) {
		$this->intThumbnailWidth = $intWidth;
		$this->intThumbnailHeight = $intHeight;
		if (!$this->set_background($strColor)) return FALSE;
		if (!$this->set_output_type($strType)) return FALSE;
		if (!empty($strCacheDir)) {
			if(!$this->set_cache_path($strCacheDir)) return FALSE;
		}
		return TRUE;
	}
	
	/**
	 * To set cache path
	 *
	 * @param string $strDir Path to cache directory. 
	 * @return boolean true when the cache directory avaliable
	 * @access public
	 */
	function set_cache_path ($strDir) {
		$this->_clear_error();
		if (!empty($strDir) && is_writable($strDir)) {
			$this->strCacheDir = $strDir;
			return TRUE;
		} else {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Cache directory is not present or unable to write';
			return FALSE;
		}
	}
	
	/**
	 * To set ImageMagick path
	 *
	 * @param string $strIMPath Path to ImageMagick. Usually are '/usr/bin/convert' or '/usr/local/bin/convert'. Set to NULL of using GDlib
	 * @return boolean true when the ImageMagick is avaliable
	 * @access public
	 */
	function set_imagemagick_path ($strIMPath = NULL) {
		$this->_clear_error();
		if (empty($strIMPath) || file_exists($strIMPath)) {
			$this->strImageMagicPath = $strIMPath;
			return TRUE;
		} else {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Invalid ImageMagick path';
			return FALSE;
		}
	}
	
	/**
	 * Assign source image path
	 *
	 * @param string $strSourceFile Path and filename of source image
	 * @return boolean true when the source is avaliable
	 * @access public
	 */
	function set_source_file ($strSourceFile) {
		$this->_clear_error();
		if (trim($strSourceFile) != '' && file_exists($strSourceFile)) {
			$this->strSourceFile = $strSourceFile;
			return TRUE;
		} else {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Invalid source image ('.$strSourceFile.')';
			return FALSE;
		}
	}
	
	/**
	 * To set thumbnail type
	 *
	 * @param string $strOutType Possible value : 'jpg', 'jpeg', 'gif' and 'png'. Default 'jpg'
	 * @return boolean true when assigned value is correct.
	 * @access public
	 */
	function set_output_type($strOutputType = 'jpg') {
		$this->_clear_error();
		$strOutputType = strtolower($strOutputType);
		if ($strOutputType=='jpg' || $strOutputType=='jpeg' || $strOutputType=='gif' || $strOutputType=='png') {
			$this->strOutputType = $strOutputType;
			return TRUE;
		} else {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Invalid output image type';
			return FALSE;
		}
	}

	/**
	 * To set thumbnail side
	 *
	 * @param integer $intWidth Thumbnail width. Default 100px
	 * @param integer $intHeight Thumbnail height. Default 100px
	 * @return void
	 * @access public
	 */
	function set_thumbnail_size($intWidth = 100, $intHeight = 100) {
		$this->intThumbnailWidth = $intWidth;
		$this->intThumbnailHeight = $intHeight;
	}
	
	/**
	 * To set thumbnail background color
	 * If background color is set. The shorter side will be filled with this color 
	 * 
	 * @param string $strColor Color string. Possible format : '#RRGGBB' & 'RRGGBB', Default NULL
	 * @return boolean when the color string is incorrect
	 * @access public
	 */
	function set_background($strColor) {
		$this->_clear_error();
		if (empty($strColor)) $this->strBgColor = NULL;
		elseif (strlen($strColor)==6) $this->strBgColor = '#'.$strColor;
		elseif (strlen($strColor)==7 && substr($strColor, 0, 1)=='#') $this->strBgColor = $strColor;
		else {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Invalid color. (Format: #RRGGBB or RRGGBB)';
			return FALSE;
		}
		return TRUE;
	}
		
	/**
	 * To set the enlarge mode
	 * If enlarge mode set to THUMBNAIL_ENLARGE_NONE(0),
	 * source will not be enlarged when the source size smaller then output size,
	 * and all space will fill with background color
	 * If enlarge mode set to THUMBNAIL_ENLARGE_ALWAYS(1),
	 * source will be enlarged to max output size.
	 * Fill mode is not applicable if no background color assigned.
	 *
	 * @param integer $intEnlargeMode Possible value : THUMBNAIL_ENLARGE_NONE(0) and THUMBNAIL_ENLARGE_ALWAYS(1)
	 * @return void
	 * @access public
	 */
	function set_enlarge_mode ($intEnlargeMode) {
		$this->intEnlargeMode = (int)$intEnlargeMode;
	}
	
	/**
	 * Output thumbnail
	 *
	 * @param string $strDest Path and filename of output file. If not provided, thumbnail will output to browser directly
	 * @return boolean true when done
	 * @access public
	 */
	function output($strDest = NULL) {
		$this->_clear_error();
		
		if (!empty($this->strSourceFile) && file_exists($this->strSourceFile)) {
			// obtain source information
			// and check enlarge mode
			$arrSourceInfo = getimagesize($this->strSourceFile);
			if (
				$this->intEnlargeMode==THUMBNAIL_ENLARGE_NONE && 
				empty($this->strBgColor) && 
				$arrSourceInfo[0] < $this->intThumbnailWidth && 
				$arrSourceInfo[1] < $this->intThumbnailHeight
			) {
				$this->intThumbnailWidth = $arrSourceInfo[0];
				$this->intThumbnailHeight = $arrSourceInfo[1];
			}
			
			// generate a thumbnail cache key
			$strThumbnailKey = md5_file($this->strSourceFile);
			$strThumbnailKey = md5($this->intThumbnailWidth."x".$this->intThumbnailHeight."_".
						((!empty($this->strImageMagicPath))?$this->strImageMagicPath."_":"").
						(($this->strOutputType=='jpg' || $this->strOutputType=='jpeg')?$this->intJPEGQuality."_":"").
						((!empty($this->strBgColor))?$this->strBgColor."_":"").
						$this->intEnlargeMode."_".
						$strThumbnailKey);
			$strCacheImageFile = "thumbnail_".$strThumbnailKey.".".$this->strOutputType;
			$strCacheImagePath = $this->strCacheDir.$strCacheImageFile;
			
			// if source is smaller then target, no enlarge, no background,
			// output type is same as source type and not found same cache
			// simply copy the source with cache name
			if (
				$this->intThumbnailWidth == $arrSourceInfo[0] && 
				$this->intThumbnailHeight == $arrSourceInfo[1] && 
				$this->_output_type2mime() == $arrSourceInfo['mime']
			) {
				if (!file_exists($strCacheImagePath)) {
					copy($this->strSourceFile, $strCacheImagePath);
				}
			}
			
			// Check cache
			if (file_exists($strCacheImagePath)) { // Cache found, use cache.
				if (empty($strDest)) { // Output to display
					$this->_send_image_header();
					readfile($strCacheImagePath);
					return TRUE;
				} else {
					copy ($strCacheImagePath, $strDest);
					return TRUE;
				}
			} else { // No cache, generate a new thumbnail
				// if ImageMagick found, always use ImageMagick
				if (!empty($this->strImageMagicPath)) {
					$boolResult = $this->_imagemagick_output($arrSourceInfo, $strCacheImagePath, $strDest);
					return $boolResult;
				} else { // no ImageMagick, use GD2
					$boolResult = $this->_gd_output($arrSourceInfo, $strCacheImagePath, $strDest);
					return $boolResult;
				}
			}
		} else {
			$this->boolError = TRUE;
			$this->strErrMsg = "Invalid source image : ".$this->strSourceFile;
			return FALSE;
		}
	}
	
//================ Private method
	/**
	 * Output HTTP header
	 *
	 * @return void
	 * @access protected
	 */
	function _send_image_header () {
		header ("Content-Type: " . $this->_output_type2mime());
		header ("Last-Modified: " . gmdate('D, d M Y H:i:s \G\M\T', time()));
		header ("Expires: Thu, 01 Jan 1970 08:00:00 GMT");
		header ("Accept-Ranges: bytes");
		header ('Pragma: no-cache');
		header ('Cache-Control: no-store, no-cache, must-revalidate');
		header ('Cache-Control: pre-check=0, post-check=0, max-age=0', FALSE);
		return;
	}
	
	/**
	 * ImageMagick output method
	 *
	 * @param array $arrSourceInfo Source image infomation including file size and file type
	 * @param string $strCacheImagePath Path and filename of cache file will be saved
	 * @param string $strDest Path and filename for saving the thumbnail. If not provided, thumbnail will output to browser directly
	 * @return boolean true when done
	 * @access protected
	 */
	function _imagemagick_output (&$arrSourceInfo, &$strCacheImagePath, $strDest=NULL) {
		if (
			$this->intThumbnailWidth==$arrSourceInfo[0] && 
			$this->intThumbnailHeight==$arrSourceInfo[1] 
		) {
			// convert source file to target image type, with cache name
			$strCmd = $this->strImageMagicPath." ".$this->strSourceFile." ".$strCacheImagePath;
		} else {
			if (empty($this->strBgColor)) { // no fill
				// resize source
				$strCmd = sprintf(IMAGEMAGICK_RESIZE_CMD, $this->strImageMagicPath, $this->intJPEGQuality, $this->intThumbnailWidth, $this->intThumbnailHeight, $this->strSourceFile, $strCacheImagePath);
			} else { // fill background
				if (
					$this->intEnlargeMode==THUMBNAIL_ENLARGE_ALWAYS || 
					$arrSourceInfo[0] > $this->intThumbnailWidth || 
					$arrSourceInfo[1] > $this->intThumbnailHeight
				) {
					// resize source with background
					$strCmd = sprintf(IMAGEMAGICK_RESIZE_FILLED_CMD, $this->strImageMagicPath, $this->strSourceFile, $this->intJPEGQuality, $this->intThumbnailWidth, $this->intThumbnailHeight, $this->intThumbnailWidth, $this->intThumbnailHeight, $this->strBgColor, $strCacheImagePath);
				} else {
					// place the source file in the middle of canvas
					$strCmd = sprintf(IMAGEMAGICK_RESIZE_FILLED_CMD, $this->strImageMagicPath, $this->strSourceFile, $this->intJPEGQuality, $arrSourceInfo[0], $arrSourceInfo[1], $this->intThumbnailWidth, $this->intThumbnailHeight, $this->strBgColor, $strCacheImagePath);
				}
			}
		}
		// execute imagemagick command
		$strExecResult = exec ($strCmd, $output, $retval);
		if ($retval)  {
			$this->boolError= TRUE;
			$this->strErrMsg = "ERROR : ImageMagick met error : ".$strExecResult;
			return FALSE;
		}
		
		if (empty($strDest)) { // Output to display
			$this->_send_image_header();
			readfile($strCacheImagePath);
			return TRUE;
		} else { // Copy cache file to target directory
			copy ($strCacheImagePath, $strDest);
			return TRUE;
		}
	}
	
	/**
	 * GDlib output method
	 *
	 * @param array $arrSourceInfo Source image infomation including file size and file type
	 * @param string $strCacheImagePath Path and filename of cache file will be saved
	 * @param string $strDest Path and filename for saving the thumbnail. If not provided, thumbnail will output to browser directly
	 * @return boolean true when done
	 * @access protected
	 */
	function _gd_output (&$arrSourceInfo, &$strCacheImagePath, $strDest=NULL) {
		if (strpos(TP_ALLOWED_IMG_TYPE, $arrSourceInfo['mime'])===FALSE) {
			$this->boolError = TRUE;
			$this->strErrMsg = 'Source file unsupported by GD';
			return FALSE;
		}
		
		// Calculate the total pixel
		// Check for GD limit : total_pixel <= memory_usable/5
		//$intMemoryAvaliable = $this->_return_bytes(ini_get('memory_limit')) - memory_get_usage();
		//$intSourceTotalPixel = $arrSourceInfo[0]*$arrSourceInfo[1];

		//if ($intMemoryAvaliable > $intSourceTotalPixel * 5) {
			switch($arrSourceInfo['mime'])
			{
				case 'image/jpeg' :
				case 'image/pjpeg' :
					$resInputImg = @imagecreatefromjpeg($this->strSourceFile);
					break;
				case 'image/gif' :
					$resInputImg = @imagecreatefromgif($this->strSourceFile);
					break;
				case 'image/png' :
					$resInputImg = @imagecreatefrompng($this->strSourceFile);
					break;
				default :
					$this->boolError = TRUE;
					$this->strErrMsg = 'Invalid output image type';
					return FALSE;
					break;
			}
			
			if ($resInputImg) {
				// obtain color's hex value
				if (!empty($this->strBgColor)) {
					$hexFillColor = '0x'.substr($this->strBgColor, 1, 6);
					eval("\$hexFillColor = ".$hexFillColor.";");
				}
				
				if (
					$this->intThumbnailWidth==$arrSourceInfo[0] && 
					$this->intThumbnailHeight==$arrSourceInfo[1]
				) {
					// Source smaller then canvas and no background
					// convert source file to target image type, with cache name
					$intCanvasWidth = $arrSourceInfo[0];
					$intCanvasHeight = $arrSourceInfo[1];
					$intOutputX = 0;
					$intOutputY = 0;
					$dblOutputWidth = $arrSourceInfo[0];
					$dblOutputHeight = $arrSourceInfo[1];
				} else {
					$intCanvasWidth = $this->intThumbnailWidth;
					$intCanvasHeight = $this->intThumbnailHeight;
					$dblWidthRatio = $arrSourceInfo[0] / $intCanvasWidth;
					$dblHeightRatio = $arrSourceInfo[1] / $intCanvasHeight;
					if (
						$this->intEnlargeMode==THUMBNAIL_ENLARGE_NONE && 
						(($arrSourceInfo[0] < $intCanvasWidth) && ($arrSourceInfo[1] < $intCanvasHeight))
					) {
						// place the source file in the middle of canvas
						$intOutputX = round(($intCanvasWidth - $arrSourceInfo[0]) / 2);
						$intOutputY = round(($intCanvasHeight - $arrSourceInfo[1]) / 2);
						$dblOutputWidth = $arrSourceInfo[0];
						$dblOutputHeight = $arrSourceInfo[1];
					} elseif ($dblWidthRatio > $dblHeightRatio) {
						$intOutputX = 0;
						$dblHeightRatio = $arrSourceInfo[1] / $arrSourceInfo[0] * ($intCanvasWidth / $intCanvasHeight);
						if (!empty($this->strBgColor)) {
							$intOutputY = round(($intCanvasHeight - ($dblHeightRatio * $intCanvasHeight)) / 2);
						} else $intOutputY = 0;
						$dblOutputWidth = $intCanvasWidth;
						$dblOutputHeight = $intCanvasHeight * $dblHeightRatio;
					} else {
						$dblWidthRatio = $arrSourceInfo[0] / $arrSourceInfo[1] * ($intCanvasHeight / $intCanvasWidth);
						if (!empty($this->strBgColor)) {
							$intOutputX = ceil(($intCanvasWidth - ($dblWidthRatio * $intCanvasWidth)) / 2);
						} else $intOutputX = 0;
						$intOutputY = 0;
						$dblOutputWidth = $intCanvasWidth * $dblWidthRatio;
						$dblOutputHeight = $intCanvasHeight;
					}
					
					if (empty($this->strBgColor)) {
						$intCanvasWidth = round($dblOutputWidth);
						$intCanvasHeight = round($dblOutputHeight);
					}
				}
				
				// Place source image on canvas
				//if ($intCanvasWidth * $intCanvasHeight * 5 < $intMemoryAvaliable) {
					$resCanvas = imagecreatetruecolor($intCanvasWidth, $intCanvasHeight);
				/*} else {
					$this->boolError = TRUE;
					$this->strErrMsg = 'Output image over-size. (Max. number of pixel allowed : '.floor($intMemoryAvaliable/5).')';
					return FALSE;
				}*/
				if (!empty($this->strBgColor)) imagefill($resCanvas, 0, 0, $hexFillColor);
				imagecopyresampled($resCanvas, $resInputImg, $intOutputX, $intOutputY, 0, 0, round($dblOutputWidth), round($dblOutputHeight), $arrSourceInfo[0], $arrSourceInfo[1]);

				// output image
				switch ($this->strOutputType) {
					case 'gif' :
						$boolResult = imagegif($resCanvas, $strCacheImagePath);
						break;
					case 'png' :
						$boolResult = imagepng($resCanvas, $strCacheImagePath);
						break;
					case 'jpg' :
					case 'jpeg' :
					default :
						$boolResult = imagejpeg($resCanvas, $strCacheImagePath, $this->intJPEGQuality);
						break;
				}
				if ($boolResult) {
					if (empty($strDest)) { // send cache to output device
						$this->_send_image_header();
						readfile($strCacheImagePath);
						imagedestroy($resInputImg);
						imagedestroy($resCanvas);
						return TRUE;
					} else { // write cache to file
						copy($strCacheImagePath, $strDest);
						imagedestroy($resInputImg);
						imagedestroy($resCanvas);
						return TRUE;
					}
				} else {
					$this->boolError = TRUE;
					$this->strErrMsg = 'GD export image failed';
				}
				if ($resInputImg) imagedestroy($resInputImg);
				if ($resCanvas) imagedestroy($resCanvas);
				return $boolResult;
			}
		/*} else { // Over memory limit, return error message
			$this->boolError= TRUE;
			$this->strErrMsg = 'Source over-size. (Max. number of pixel allowed : '.floor($intMemoryAvaliable/5).')';
			return FALSE;
		}*/
	}
	
	/**
	 * Convert image type to mime type string
	 *
	 * @param string $strImageType Image type string. Use native image type when no prarmeter
	 * @return string MIME type
	 * @access protected
	 */
	function _output_type2mime ($strImageType=NULL) {
		if (empty($strImageType)) $strImageType = &$this->strOutputType;
		switch ($strImageType) {
			case 'gif' :
				return 'image/gif';
				break;
			case 'png' :
				return 'image/png';
				break;
			case 'jpg' :
			case 'jpeg' :
			default :
				return 'image/jpeg';
				break;
		}
	}
	
	/**
	 * Convert shorten form file size to byte
	 * Original from PHP.NET
	 *
	 * @param string $strVal Human readable file size string
	 * @return integer Byte value
	 * @access protected
	 */
	function _return_bytes($strVal) {
	   $strVal = str_replace(" ", "", trim($strVal));
	   preg_match("/[a-zA-Z]{1,2}/", $strVal, $match);
	   $unit = (isset($match[0])) ? strtolower($match[0]) : "";
	   $amount = (float)str_replace($unit, "", $strVal);
	   switch($unit) {
	       // The 'G' modifier is available since PHP 5.1.0
	       case 't':
	       case 'tb':
	           $amount *= 1024;
	       case 'g':
	       case 'gb':
	           $amount *= 1024;
	       case 'm':
	       case 'mb':
	           $amount *= 1024;
	       case 'k':
	       case 'kb':
	           $amount *= 1024;
	   }
	
	   return round($amount);
	}
	
//================ Method for error reporting
	/**
	 * Obtain error status of the class
	 *
	 * @return boolean true if there is any error
	 * @access public
	 */
	function isError () {
		return $this->boolError;
	}
	
	/**
	 * Obtain last error message
	 *
	 * @return string Error message
	 * @access public
	 */
	function get_error_msg () {
		return $this->strErrMsg;
	}
	
	/**
	 * Reset error status and error message
	 *
	 * @return void
	 * @access protected
	 */
	function _clear_error () {
		$this->boolError = FALSE;
		$this->strErrMsg = '';
	}
	
	/**
	 * To print some message on picture for debug
	 *
	 * @param resource $resImg The image resource that the message will be placed in.
	 * @param string $strMsg The message
	 * @return void
	 * @access protected
	 */
	function _gd_print_msg (&$resImg, $strMsg) {
		$arrMsg = explode("\n", wordwrap($strMsg,15,"\n",TRUE));
		for ($i=0; $i < count($arrMsg); $i++) {
			imagestring($resImg, 2, 1, $i*12+1, $arrMsg[$i], 0xFFFFFF);
			imagestring($resImg, 2, 0, $i*12, $arrMsg[$i], 0xFF0000);
		}
	}
}
?>
